#include "link.h"



/* ****************************************************
 *
 * Private Methods
 *
 * ***************************************************/

bool Link::GetTargetLabelBit(void)
{
  return ((INITIALBITPOSITION >> uint32_LabelBitPosition) & uint32_TargetLabel);
}

bool Link::GetBuildLabelBit(void)
{
  return ((INITIALBITPOSITION >> uint32_LabelBitPosition) & uint32_BuildLabel);
}

void Link::SetCurrentBuildLabelBit(void)
{
  if(b_DataLineBuffer)
  {
    uint32_BuildLabel |= (INITIALBITPOSITION >> uint32_LabelBitPosition);
  }
}

/* ****************************************************
 *
 * Public Methods
 *
 * ***************************************************/

Link::Link(bool * dataLine)
{
  e_ClockState = STATE1;

  pb_DataLine = dataLine;

  b_DataLineBuffer = 0;
  b_LinkResetFromHost = 0;
  b_LinkResetFromNeighbor = 0;
  uint32_TargetLabel = 0;
  uint32_BuildLabel = 0;

  b_LinkKilled = false;
  ResetBitPosition();

}

Link::~Link(void)
{
}

void Link::ClockLink(void)
{
  switch(e_ClockState)
  {
    /* RESET STATE */
    case STATE1:
      /* set data line if host requests it */
      *pb_DataLine |= b_LinkResetFromHost;
      e_ClockState = STATE2;
      break;
    case STATE2:
      /* read data line for reset */
      b_DataLineBuffer = *pb_DataLine;
      e_ClockState = STATE3;
      break;
    case STATE3:
      /* set output to host that a reset has occured */
      b_LinkResetFromNeighbor = b_DataLineBuffer;
      e_ClockState = STATE4;
      break;
    case STATE4:
      /* check to see if a reset has occured */
      if(b_LinkResetFromHost || b_LinkResetFromNeighbor)
      {
        ResetBitPosition();
        uint32_BuildLabel = 0;
      }
      e_ClockState = STATE5;
      break;
    case STATE5:
      /* clear all data for next clock cycle */
      *pb_DataLine = 0;
      b_DataLineBuffer = 0;
      b_LinkResetFromHost = 0;
      /* reseting clock cycle */
      e_ClockState = STATE6;
      break;
    /* COM STATE */
    case STATE6:
      if(SEND == e_LinkComMode)
      {
        /* setting data line */
        *pb_DataLine |= GetTargetLabelBit();
      }
      else
      {
        /* do nothing for RECEIVING MODE */
      }
      e_ClockState = STATE7;
      break;
    case STATE7:
      /* read data line in both Com Modes */
      b_DataLineBuffer = *pb_DataLine;
      e_ClockState = STATE8;
      break;
    case STATE8:
      if(SEND == e_LinkComMode)
      {
        /* check to see if data line is hi */
        if(b_DataLineBuffer)
        {
          if(0 != uint32_LabelBitPosition)
          {
            /* check to see if host processor wrote a hi bit */
            if(!GetTargetLabelBit())
            {
              /* changing to receive because neighbor is dominant */
              e_LinkComMode = RECEIVE;
            }
          }
          else
          {
            e_LinkComMode = COMPLETE;
            b_LinkKilled = true;
          }
        }
      }
      else
      {
        /* do nothing for RECEIVING MODE */
      }
      e_ClockState = STATE9;
      break;
    case STATE9:
      /* write to the build label in both Com Modes */
      SetCurrentBuildLabelBit();
      e_ClockState = STATE10;
      break;
    case STATE10:
      /* increment label bit position */
      IncrementBitPosition();
      e_ClockState = STATE1;

      /* reset physical link */
      *pb_DataLine = 0;
      break;
    
    default:
      break;
  } /* end switch(e_ClockState) */
}

void Link::ResetBitPosition(void)
{
  uint32_LabelBitPosition = 0;
  uint32_DisplayLabelBitPosition = 0;
  e_LinkComMode = SEND;
}

void Link::IncrementBitPosition(void)
{
  if(uint32_LabelBitPosition > 0)
  {
    if(uint32_DisplayLabelBitPosition < 31) uint32_DisplayLabelBitPosition++;
  }

  if(uint32_LabelBitPosition < 31)
  {
    uint32_LabelBitPosition++;
  }
  else
  {
    e_LinkComMode = COMPLETE;
  }
}

void Link::SetTargetLabel(unsigned int targetLabel)
{
  uint32_TargetLabel = targetLabel;
}

void Link::SetLinkResetFromHost(void)
{
  b_LinkResetFromHost = 1;
}

unsigned int Link::ReadTargetLabel(void)
{
  return uint32_TargetLabel;
}

unsigned int Link::ReadBuildLabel(void)
{
  return uint32_BuildLabel;
}

unsigned int Link::ReadLabelBitPosition(void)
{
  return uint32_DisplayLabelBitPosition;
}

bool Link::ReadResetFromNeighbor(void)
{
  return b_LinkResetFromNeighbor;
}

bool * Link::GetPhysicalLinkAddress(void)
{
  return pb_DataLine;
}

bool Link::IsLinkActive(void)
{
  return !b_LinkKilled;
}

bool Link::IsLinkComplete(void)
{
  return (COMPLETE == e_LinkComMode);
}

void Link::PrintLinkData(void)
{

  std::cout << std::endl;
  std::cout << "Target Label: " << uint32_TargetLabel << std::endl;
  std::cout << "Build Label: " << uint32_BuildLabel << std::endl;
  std::cout << "Label Bit Position: " << uint32_LabelBitPosition << std::endl;
  std::cout << "Data Line: " << *pb_DataLine << std::endl;
  std::cout << "Data Line Buffer: " << b_DataLineBuffer << std::endl;
  std::cout << "Link Reset From Neighbor: " << b_LinkResetFromNeighbor << std::endl;
  std::cout << "Link Reset From Host: " << b_LinkResetFromHost << std::endl;
  std::cout << "Link Killed: " << b_LinkKilled << std::endl;

}
